package logx

import (
	"context"
	"log"
	"os"
	"strings"
	"sync"
	"time"
)

/**
使用 log.Lshortfile 支持显示文件名和代码行号。
*/
var (
	errorLog = log.New(os.Stdout, "\033[31m[error]\033[0m ", log.LstdFlags|log.Lshortfile)
	infoLog  = log.New(os.Stdout, "\033[34m[info ]\033[0m ", log.LstdFlags|log.Lshortfile)
	loggers  = []*log.Logger{errorLog, infoLog}
)

//var (
//	Error  = errorLog.Println
//	Errorf = errorLog.Printf
//	Info   = infoLog.Println
//	Infof  = infoLog.Printf
//)

type (
	// LogField is a key-value pair that will be added to the log entry.
	LogField struct {
		Key   string
		Value interface{}
	}

	logEntry map[string]interface{}

	LogConfig struct {
		Level       string
		Type        string
		LogSavePath string
		Format      string
		MaxSize     int
		MaxAge      int
		MaxBackups  int
	}
)

var (
	std  ILogger
	once sync.Once
)

type ILogger interface {
	Trace(args ...interface{})
	Debug(args ...interface{})
	Info(args ...interface{})
	Warn(args ...interface{})
	Error(args ...interface{})
	Panic(args ...interface{})
	Fatal(args ...interface{})

	Tracef(format string, args ...interface{})
	Debugf(format string, args ...interface{})
	Infof(format string, args ...interface{})
	Warnf(format string, args ...interface{})
	Errorf(format string, args ...interface{})
	Panicf(format string, args ...interface{})
	Fatalf(format string, args ...interface{})

	SetOutputLevel(level string)

	// WithCallerSkip returns a new logger with the given caller skip.
	WithCallerSkip(skip int) ILogger
	// WithContext returns a new logger with the given context.
	WithContext(ctx context.Context) ILogger
	// WithDuration returns a new logger with the given duration.
	WithDuration(d time.Duration) ILogger
	// WithFields returns a new logger with the given fields.
	WithFields(fields ...LogField) ILogger
}

func NewGlobalLog(cfg *LogConfig) ILogger {
	once.Do(func() {
		if cfg.Type == "" {
			cfg.Type = "logrus"
		}
		switch strings.ToLower(cfg.Type) {
		case "logrus":
			std = NewLogrusAdapt(cfg)
		case "zap":
			std = NewZapAdapt(cfg)
		default:
			std = NewLogrusAdapt(cfg)
		}
	})
	return std
}

func Trace(args ...interface{}) {
	std.Trace(args...)
}

func Tracef(format string, args ...interface{}) {
	std.Tracef(format, args...)
}

func Debug(args ...interface{}) {
	std.Debug(args...)
}

func Debugf(format string, args ...interface{}) {
	std.Debugf(format, args...)
}

func Info(args ...interface{}) {
	std.Info(args...)
}

func Infof(format string, args ...interface{}) {
	std.Infof(format, args...)
}

func Warn(args ...interface{}) {
	std.Warn(args...)
}

func Warnf(format string, args ...interface{}) {
	std.Warnf(format, args...)
}

func Error(args ...interface{}) {
	std.Error(args...)
}

func Errorf(format string, args ...interface{}) {
	std.Errorf(format, args...)
}

func Panic(args ...interface{}) {
	std.Panic(args...)
}

func Panicf(format string, args ...interface{}) {
	std.Panicf(format, args...)
}

func Fatal(args ...interface{}) {
	std.Fatal(args...)
}

func Fatalf(format string, args ...interface{}) {
	std.Fatalf(format, args...)
}
